package response

import (
	"errors"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
)

type Response struct {
	Code      string `json:"code"`
	Message   string `json:"message"`
	Data      any    `json:"result"`
	Timestamp int64  `json:"timestamp"`
}

// NewErrorResponse 创建一个表示成功响应的Response对象。
// 该函数主要用于在系统中统一生成成功的响应消息，以减少代码重复和提高可维护性。
// 参数:
//
//	err - 一个错误对象，此处总是传递ErrSuccess，表示操作成功。
//
// 返回值:
//
//	*Response - 指向新创建的Response对象的指针。
//	Response对象包含了操作的成功代码、成功消息、空的数据映射以及当前的时间戳。
func NewErrorResponse(err error) *Response {
	// 返回一个新的Response对象，其中包含了操作成功的代码和消息。
	// Data字段初始化为空的字符串映射，Timestamp字段设置为当前的Unix时间戳。
	return &Response{
		Code:      errorCodeMap[err],
		Message:   err.Error(),
		Data:      map[string]string{},
		Timestamp: time.Now().Unix(),
	}
}

// NewResponse 创建一个新的响应对象。
// 它用于封装操作的结果，包括状态码、错误信息、数据和时间戳。
// 参数:
//
//	code: 操作的状态码，表示操作的成功与否或其他状态。
//	err: 操作可能产生的错误，如果操作成功，则可以为nil。
//	data: 操作返回的数据，可以是任何类型。如果操作没有返回数据，可以为nil。
//
// 返回值:
//
//	*Response: 返回一个指向新创建的响应对象的指针。
func NewResponse(code string, err error, data any) *Response {
	// 如果没有提供状态码，则使用表示成功的默认状态码。
	if code == "" {
		code = errorCodeMap[ErrSuccess]
	}

	// 如果没有提供数据，则使用一个空的map作为默认数据。
	// 这样做是为了确保响应中的Data字段始终可用，避免外部调用时的空指针异常。
	if data == nil {
		data = map[string]string{}
	}

	// 创建并返回一个新的响应对象，包含状态码、错误信息、数据和当前时间戳。
	return &Response{
		Code:      code,
		Message:   err.Error(),
		Data:      data,
		Timestamp: time.Now().Unix(),
	}
}

func HandleSuccess(ctx *gin.Context, data any) {
	if data == nil {
		data = map[string]any{}
	}

	resp := NewErrorResponse(ErrSuccess)
	if _, ok := errorCodeMap[ErrSuccess]; !ok {
		resp.Code = "0000000"
		resp.Message = ""
	}

	resp.Data = data
	ctx.JSON(http.StatusOK, resp)
}

func HandleError(ctx *gin.Context, httpCode int, err error) {
	// code, ok := errorCodeMap[err]
	// if !ok {
	// 	code = "500"
	// }

	code := "500"
	resp := NewResponse(code, err, nil)
	if _, ok := errorCodeMap[ErrSuccess]; !ok {
		resp.Code = "500"
		resp.Message = "unknown error"
	}
	ctx.JSON(httpCode, resp)
}

type Error struct {
	Code    string
	Message string
}

var errorCodeMap = map[error]string{}

func newError(code string, msg string) error {
	err := errors.New(msg)
	errorCodeMap[err] = code
	return err
}
func (e Error) Error() string {
	return e.Message
}
